#pragma once
#include <format>
#include <string>
#include <utility>

#include "Calendar/LunarConstants.hpp"

// Heavenly Stems (Tiangan)
// https://en.wikipedia.org/wiki/Heavenly_Stems
enum class HeavenlyStem
{
    Jia  = 0,
    Yi   = 1,
    Bing = 2,
    Ding = 3,
    Wu   = 4,
    Ji   = 5,
    Geng = 6,
    Xin  = 7,
    Ren  = 8,
    Gui  = 9,
};
// Heavenly Stems Max
#define HeavenlyStemMax (static_cast<unsigned int>(HeavenlyStem::Gui) + 1)

// Earthly Branches (Dizhi)
// https://en.wikipedia.org/wiki/Earthly_Branches
enum class EarthlyBranch
{
    Zi   = 0,
    Chou = 1,
    Yin  = 2,
    Mao  = 3,
    Chen = 4,
    Si   = 5,
    Wu   = 6,
    Wei  = 7,
    Shen = 8,
    You  = 9,
    Xu   = 10,
    Hai  = 11,
};
// Earthly Branches  Max;
#define EarthlyBranchMax (static_cast<unsigned int>(EarthlyBranch::Hai) + 1)

// SexagenaryCycle maxinum;
#define SexagenaryCycleMaximum (60)

class SexagenaryCycle
{
public:
    /**
     * @brief 将周期索引值转换成天干及地支索引
     *
     * @param ordinal 周期索引值[0 - 59]
     * @return std::pair<HeavenlyStem, EarthlyBranch> HeavenlyStem = 天干序号[0 - 9],EarthlyBranch = 地支序号 [0 - 11];
     */
    static std::pair<HeavenlyStem, EarthlyBranch> FromOrdinal(unsigned int ordinal) noexcept;

    /**
     * @brief 将天干及地支索引转换成周期索引值
     *
     * @param heanvenlyStem 天干序号[0 - 9];
     * @param earthlyBranch 地支序号[0 - 11];
     * @return int 返回值 { 成功：大于等于零[0 - 59], 失败：-1};
     */
    static int ToOrdinal(HeavenlyStem heanvenlyStem, EarthlyBranch earthlyBranch) noexcept;

    // 构造函数;
public:
    SexagenaryCycle(void) : SexagenaryCycle(HeavenlyStem::Jia, EarthlyBranch::Zi) {};
    SexagenaryCycle(HeavenlyStem heanvenlyStem, EarthlyBranch earthlyBranch)
    {
        auto value = ToOrdinal(heanvenlyStem, earthlyBranch);
        if (value != -1)
        {
            this->ordinal       = value;
            this->heanvenlyStem = heanvenlyStem;
            this->earthlyBranch = earthlyBranch;
        }
    };
    SexagenaryCycle(unsigned int ordinal) { *this = ordinal; };
    SexagenaryCycle(const SexagenaryCycle &cycle) { *this = cycle; };

    std::string ToString()
    {
        return std::format("{}{}", LunarConstants::CnHeavenlyStems[(int)this->heanvenlyStem], LunarConstants::CnEarthlyBranches[(int)this->earthlyBranch]);
    }

public:
    SexagenaryCycle &operator=(unsigned int ordinal)
    {
        ordinal %= 60;
        auto [hs, eb]       = SexagenaryCycle::FromOrdinal(ordinal);

        this->heanvenlyStem = hs;
        this->earthlyBranch = eb;
        this->ordinal       = ordinal;
        return *this;
    }
    SexagenaryCycle &operator=(const SexagenaryCycle &sc)
    {
        if (this != &sc)
        {
            this->earthlyBranch = sc.earthlyBranch;
            this->heanvenlyStem = sc.heanvenlyStem;
            this->ordinal       = sc.ordinal;
        }
        return *this;
    }

    inline bool operator==(const SexagenaryCycle &sc) const { return this->ordinal == sc.ordinal; }

public:
    HeavenlyStem  heanvenlyStem;
    EarthlyBranch earthlyBranch;
    unsigned int  ordinal;
};

class SexagenaryCycleDate
{
public:
    SexagenaryCycleDate() {}
    /**
     * @brief 构造函数:计算本地干支纪元;
     *
     * @param jd
     *        2000 起算的儒略日;
     * @param localLongitude
     *        监测站经度[单位:角秒]
     */
    SexagenaryCycleDate(double jd, double localLongitude);

    std::string ToString()
    {
        return std::format(
            "{} {} {} {}", this->scYear.ToString().c_str(), this->scMonth.ToString().c_str(), this->scDay.ToString().c_str(), this->scHour.ToString().c_str());
    }

public:
    // 日期时间型;
    // 纪年;
    SexagenaryCycle scYear;
    // 纪月;
    SexagenaryCycle scMonth;
    // 纪日;
    SexagenaryCycle scDay;
    // 纪时;
    SexagenaryCycle scHour;

    // 儒略日数及时间(小数部分);
    double dateJulianDay;
    // 本地经度;
    double dateLocalLongitude;
    // 真太阳时;
    double apparentSolarTimeJd;
};